namespace Microsoft.ServiceModel.Samples.Discovery
{
    using System;
    using System.ServiceModel;
    using System.Xml;

    public class ServicePropertiesMatcher : IServicePropertiesMatcher
    {
        public bool IsMatch(ServiceProperties properties,
            MatchCriteria criteria)
        {
            if (properties == null)
                throw new ArgumentNullException("properties");

            if (criteria == null)
                throw new ArgumentNullException("criteria");

            bool isMatch = true;
            if (isMatch) isMatch = MatchTypes(properties, criteria);
            if (isMatch) isMatch = MatchScopes(properties, criteria);

            return isMatch;
        }

        public bool IsMatch(ServiceProperties properties, 
            EndpointAddress address)
        {
            if (properties == null)
                throw new ArgumentNullException("properties");

            if (address == null)
                throw new ArgumentNullException("address");

            return address.Equals(properties.EndpointAddress);
        }

        static bool MatchTypes(ServiceProperties props, MatchCriteria criteria)
        {
            if ((criteria.Types == null) || (criteria.Types.Count == 0)) 
                return true;

            if ((props.Types == null) || (props.Types.Count == 0)) 
                return false;

            foreach (XmlQualifiedName type in criteria.Types)
            {
                if (!props.Types.Contains(type)) 
                    return false;
            }

            return true;
        }

        static bool MatchScopes(ServiceProperties props, MatchCriteria criteria)
        {
            if ((criteria.Scopes == null) || (criteria.Scopes.Count == 0)) 
                return true;

            if ((props.Scopes == null) || (props.Scopes.Count == 0)) 
                return false;

            string[] compiledScopes = null;
            if (props.CompiledScopesSpecified)
                compiledScopes = props.CompiledScopes;
            else
                compiledScopes = ScopeCompiler.Compile(props.Scopes);

            foreach (Uri scope in criteria.Scopes)
            {
                if (!ScopeCompiler.IsMatch(compiledScopes, scope, 
                    criteria.Scopes.MatchBy))
                {
                    return false;
                }
            }

            return true;
        }
    }
}
